看著團隊挑戰的成員寫了一篇 從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰,那我們今天就來挑戰看看怎麼在 flutter 上開發遊戲好了。
這是一套在 Flutter 上的 2D 遊戲引擎。
目前穩定版本是 0.29.4
,不過預發佈版本已來到 flame 1.0.0-releasecandidate.14
,兩邊的語法寫法不大相同,研究前請注意一下。
在官網上文件尚不完整,建議參考awesome-flame
上的教學文章。
至 pubspec.yaml
加入套件設定
dependencies:
...
flame: ^1.0.0-releasecandidate.14
...
想起以前在研究 Cocos Creator 時的 星星 遊戲,想說試著用 flame
來開發看看,我們從 cocos-creator GitHub 上可以取得圖片素材。
import 'package:flutter/material.dart';
import 'package:flame/flame.dart';
import 'package:flame/game.dart';
void main() async {
// 確認 Flutter 已剛成初始化綁定動作
WidgetsFlutterBinding.ensureInitialized();
// 設定全屏以及橫向顯示
Flame.device.fullScreen();
Flame.device.setLandscape();
runApp(const StarsApp());
}
目前 1.0.0
的語法,需使用 GameWidget
帶入 game
參數。
class StarsApp extends StatelessWidget {
const StarsApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Stars',
theme: ThemeData.dark(),
home: Scaffold(body: GameWidget(game: StarGame())),
);
}
}
import 'package:flame/game.dart';
class StarGame extends FlameGame {
// 取得 App 畫面寬高
final double screenWidth = MediaQueryData.fromWindow(window).size.width;
final double screenHeight = MediaQueryData.fromWindow(window).size.height;
@override
Future<void> onLoad() async {
// TODO
}
}
與 Flutter 在使用圖片方式一樣,在 pubspec.yaml
的 assets
定義圖片來源。
flutter:
uses-material-design: true
assets:
- assets/images/
在 StarGame
屬性定義會使用到的圖片設定
static const _assetsImages = [
'purple_moster.png',
'background.jpg',
'ground.png',
'star.png'
];
使用 FlameGame
的 images
戴入
Future<void> onLoad() async {
await images.loadAll(_assetsImages);
}
我們使用 SpriteComponent
定義 Sprite
內容,這個 Component
提供 size
、position
參數可對應畫面上的設定。
class SpriteComponent extends PositionComponent with HasPaint {
/// The [sprite] to be rendered by this component.
Sprite? sprite;
/// Creates a component with an empty sprite which can be set later
SpriteComponent({
Vector2? position,
Vector2? size,
int? priority,
this.sprite,
Paint? paint,
}) : super(
position: position,
size: size ?? sprite?.srcSize,
priority: priority,
) {
if (paint != null) {
this.paint = paint;
}
}
使用 SpriteComponent
來設定背景圖片,從 size
指定元件的寬高
import 'package:flame/components.dart';
import 'star_game.dart';
class Background extends SpriteComponent {
Background(StarGame _game)
: super(
sprite: Sprite(
_game.images.fromCache('background.jpg'),
),
size: Vector2(_game.screenWidth, _game.screenHeight),
);
}
使用 add
將 Component
新增至畫面上
Future<void> onLoad() async {
await images.loadAll(_assetsImages);
final background = Background(this);
add(background);
}
import 'package:flame/components.dart';
import 'star_game.dart';
class Ground extends SpriteComponent {
final double _height = 100;
final StarGame _game;
Ground(this._game)
: super(sprite: Sprite(_game.images.fromCache('ground.png'))) {
size = Vector2(_game.screenWidth, _height);
position = Vector2(0, _game.screenHeight - _height);
}
}
import 'package:flame/components.dart';
import 'star_game.dart';
class Moster extends SpriteComponent with Hitbox, Collidable {
late final StarGame _game;
Moster(this._game)
: super(
sprite: Sprite(_game.images.fromCache('purple_moster.png')),
size: Vector2(64, 64),
) {
x = 200;
y = _originY = _game.screenHeight - _game.ground.height - height / 2;
anchor = Anchor.center;
}
今日成果